//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at  http://www.nopCommerce.com/License.aspx. 
// 
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. 
// See the License for the specific language governing rights and limitations under the License.
// 
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
// 
// Contributor(s): _______. 
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using NopSolutions.NopCommerce.BusinessLogic.Caching;
using NopSolutions.NopCommerce.BusinessLogic.Configuration.Settings;
using NopSolutions.NopCommerce.BusinessLogic.Data;
using NopSolutions.NopCommerce.BusinessLogic.Infrastructure;
using NopSolutions.NopCommerce.Common.Utils;

namespace NopSolutions.NopCommerce.BusinessLogic.Stores
{
    /// <summary>
    /// Manufacturer service
    /// </summary>
    public partial class StoreService : IStoreService
    {
        #region Constants
        private const string STORES_ALL_KEY = "Nop.store.all-{0}";
        private const string STORES_BY_ID_KEY = "Nop.store.id-{0}";
        private const string PRODUCTSTORES_ALLBYSTORERID_KEY = "Nop.productstore.allbymanufacturerid-{0}-{1}";
        private const string PRODUCTSTORES_ALLBYPRODUCTID_KEY = "Nop.productstore.allbyproductid-{0}-{1}";
        private const string PRODUCTSTORES_BY_ID_KEY = "Nop.productstore.id-{0}";
        private const string STORES_PATTERN_KEY = "Nop.store.";
        private const string PRODUCTSTORES_PATTERN_KEY = "Nop.productstore.";
        #endregion

        #region Fields

        /// <summary>
        /// Object context
        /// </summary>
        private readonly NopObjectContext _context;

        /// <summary>
        /// Cache manager
        /// </summary>
        private readonly ICacheManager _cacheManager;

        #endregion

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="context">Object context</param>
        public StoreService(NopObjectContext context)
        {
            this._context = context;
            this._cacheManager = new NopRequestCache();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Marks a manufacturer as deleted
        /// </summary>
        /// <param name="manufacturerId">Manufacturer identifer</param>
        public void MarkStoreAsDeleted(int storeId)
        {
            var store = GetStoreById(storeId);
            if (store != null)
            {
                store.Deleted = true;
                UpdateStore(store);
            }
        }

        /// <summary>
        /// Gets all manufacturers OK
        /// </summary>
        /// <returns>Manufacturer collection</returns>
        public List<Store> GetAllStores()
        {
            bool showHidden = NopContext.Current.IsAdmin;
            return GetAllStores(showHidden);
        }

        /// <summary>
        /// Gets all Stores OK
        /// </summary>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>Store collection</returns>
        public List<Store> GetAllStores(bool showHidden)
        {
            string key = string.Format(STORES_ALL_KEY, showHidden);
            object obj2 = _cacheManager.Get(key);
            if (this.StoresCacheEnabled && (obj2 != null))
            {
                return (List<Store>)obj2;
            }

            
            var query = from m in _context.Stores
                        orderby m.DisplayOrder
                        where (showHidden || m.Published) &&
                        !m.Deleted
                        select m;
            var stores = query.ToList();

            if (this.StoresCacheEnabled)
            {
                _cacheManager.Add(key, stores);
            }
            return stores;
        }

        /// <summary>
        /// Gets a manufacturer OK
        /// </summary>
        /// <param name="storeId">Store identifier</param>
        /// <returns>Store</returns>
        public Store GetStoreById(int storeId)
        {
            if (storeId == 0)
                return null;

            string key = string.Format(STORES_BY_ID_KEY, storeId);
            object obj2 = _cacheManager.Get(key);
            if (this.StoresCacheEnabled && (obj2 != null))
            {
                return (Store)obj2;
            }

            
            var query = from m in _context.Stores
                        where m.StoreId == storeId
                        select m;
            var store = query.SingleOrDefault();

            if (this.StoresCacheEnabled)
            {
                _cacheManager.Add(key, store);
            }
            return store;
        }

        /// <summary>
        /// Inserts a store OK
        /// </summary>
        /// <param name="manufacturer">Store</param>
        public void InsertStore(Store store)
        {
            if (store == null)
                throw new ArgumentNullException("store");

            store.Name = CommonHelper.EnsureNotNull(store.Name);
            store.Name = CommonHelper.EnsureMaximumLength(store.Name, 400);
            store.Description = CommonHelper.EnsureNotNull(store.Description);
            store.MetaKeywords = CommonHelper.EnsureNotNull(store.MetaKeywords);
            store.MetaKeywords = CommonHelper.EnsureMaximumLength(store.MetaKeywords, 400);
            store.MetaDescription = CommonHelper.EnsureNotNull(store.MetaDescription);
            store.MetaDescription = CommonHelper.EnsureMaximumLength(store.MetaDescription, 400);
            store.MetaTitle = CommonHelper.EnsureNotNull(store.MetaTitle);
            store.MetaTitle = CommonHelper.EnsureMaximumLength(store.MetaTitle, 400);
            store.SEName = CommonHelper.EnsureNotNull(store.SEName);
            store.SEName = CommonHelper.EnsureMaximumLength(store.SEName, 100);
            store.PriceRanges = CommonHelper.EnsureNotNull(store.PriceRanges);
            store.PriceRanges = CommonHelper.EnsureMaximumLength(store.PriceRanges, 400);



            _context.Stores.AddObject(store);
            _context.SaveChanges();

            if (this.StoresCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(STORES_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTSTORES_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Updates the store OK
        /// </summary>
        /// <param name="manufacturer">Store</param>
        public void UpdateStore(Store store)
        {
            if (store == null)
                throw new ArgumentNullException("store");

            store.Name = CommonHelper.EnsureNotNull(store.Name);
            store.Name = CommonHelper.EnsureMaximumLength(store.Name, 400);
            store.Description = CommonHelper.EnsureNotNull(store.Description);
            store.MetaKeywords = CommonHelper.EnsureNotNull(store.MetaKeywords);
            store.MetaKeywords = CommonHelper.EnsureMaximumLength(store.MetaKeywords, 400);
            store.MetaDescription = CommonHelper.EnsureNotNull(store.MetaDescription);
            store.MetaDescription = CommonHelper.EnsureMaximumLength(store.MetaDescription, 400);
            store.MetaTitle = CommonHelper.EnsureNotNull(store.MetaTitle);
            store.MetaTitle = CommonHelper.EnsureMaximumLength(store.MetaTitle, 400);
            store.SEName = CommonHelper.EnsureNotNull(store.SEName);
            store.SEName = CommonHelper.EnsureMaximumLength(store.SEName, 100);
            store.PriceRanges = CommonHelper.EnsureNotNull(store.PriceRanges);
            store.PriceRanges = CommonHelper.EnsureMaximumLength(store.PriceRanges, 400);


            if (!_context.IsAttached(store))
                _context.Stores.Attach(store);

            _context.SaveChanges();

            if (this.ManufacturersCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(STORES_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTSTORES_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Gets localized store by id OK
        /// </summary>
        /// <param name="manufacturerLocalizedId">Localized store identifier</param>
        /// <returns>Manufacturer content</returns>
        public StoreLocalized GetStoreLocalizedById(int storeLocalizedId)
        {
            if (storeLocalizedId == 0)
                return null;


            var query = from ml in _context.StoreLocalized
                        where ml.StoreLocalizedID == storeLocalizedId
                        select ml;
            var storeLocalized = query.SingleOrDefault();
            return storeLocalized;
        }

        /// <summary>
        /// Gets localized store by store id OK
        /// </summary>
        /// <param name="manufacturerId">Store identifier</param>
        /// <returns>Store content</returns>
        public List<StoreLocalized> GetStoreLocalizedByStoreId(int storeId)
        {
            if (storeId == 0)
                return new List<StoreLocalized>();


            var query = from ml in _context.StoreLocalized
                        where ml.StoreLocalizedID == storeId
                        select ml;
            var content = query.ToList();
            return content;
        }

        /// <summary>
        /// Gets localized store by store id and language id OK
        /// </summary>
        /// <param name="manufacturerId">Store identifier</param>
        /// <param name="languageId">Language identifier</param>
        /// <returns>Store content</returns>
        public StoreLocalized GetStoreLocalizedByStoreIdAndLanguageId(int storeId, int languageId)
        {
            if (storeId == 0 || languageId == 0)
                return null;


            var query = from ml in _context.StoreLocalized
                        orderby ml.StoreLocalizedID
                        where ml.StoreID == storeId &&
                        ml.LanguageID == languageId
                        select ml;
            var storeLocalized = query.FirstOrDefault();
            return storeLocalized;
        }

        /// <summary>
        /// Inserts a localized manufacturer OK
        /// </summary>
        /// <param name="manufacturerLocalized">Store content</param>
        public void InsertStoreLocalized(StoreLocalized storeLocalized)
        {
            if (storeLocalized == null)
                throw new ArgumentNullException("storeLocalized");

            storeLocalized.Name = CommonHelper.EnsureNotNull(storeLocalized.Name);
            storeLocalized.Name = CommonHelper.EnsureMaximumLength(storeLocalized.Name, 400);
            storeLocalized.Description = CommonHelper.EnsureNotNull(storeLocalized.Description);
            storeLocalized.MetaKeywords = CommonHelper.EnsureNotNull(storeLocalized.MetaKeywords);
            storeLocalized.MetaKeywords = CommonHelper.EnsureMaximumLength(storeLocalized.MetaKeywords, 400);
            storeLocalized.MetaDescription = CommonHelper.EnsureNotNull(storeLocalized.MetaDescription);
            storeLocalized.MetaDescription = CommonHelper.EnsureMaximumLength(storeLocalized.MetaDescription, 400);
            storeLocalized.MetaTitle = CommonHelper.EnsureNotNull(storeLocalized.MetaTitle);
            storeLocalized.MetaTitle = CommonHelper.EnsureMaximumLength(storeLocalized.MetaTitle, 400);
            storeLocalized.SEName = CommonHelper.EnsureNotNull(storeLocalized.SEName);
            storeLocalized.SEName = CommonHelper.EnsureMaximumLength(storeLocalized.SEName, 100);



            _context.StoreLocalized.AddObject(storeLocalized);
            _context.SaveChanges();

            if (this.StoresCacheEnabled)
            {
                _cacheManager.RemoveByPattern(STORES_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Update a localized store OK
        /// </summary>
        /// <param name="manufacturerLocalized">Store content</param>
        public void UpdateStoreLocalized(StoreLocalized storeLocalized)
        {
            if (storeLocalized == null)
                throw new ArgumentNullException("manufacturerLocalized");

            storeLocalized.Name = CommonHelper.EnsureNotNull(storeLocalized.Name);
            storeLocalized.Name = CommonHelper.EnsureMaximumLength(storeLocalized.Name, 400);
            storeLocalized.Description = CommonHelper.EnsureNotNull(storeLocalized.Description);
            storeLocalized.MetaKeywords = CommonHelper.EnsureNotNull(storeLocalized.MetaKeywords);
            storeLocalized.MetaKeywords = CommonHelper.EnsureMaximumLength(storeLocalized.MetaKeywords, 400);
            storeLocalized.MetaDescription = CommonHelper.EnsureNotNull(storeLocalized.MetaDescription);
            storeLocalized.MetaDescription = CommonHelper.EnsureMaximumLength(storeLocalized.MetaDescription, 400);
            storeLocalized.MetaTitle = CommonHelper.EnsureNotNull(storeLocalized.MetaTitle);
            storeLocalized.MetaTitle = CommonHelper.EnsureMaximumLength(storeLocalized.MetaTitle, 400);
            storeLocalized.SEName = CommonHelper.EnsureNotNull(storeLocalized.SEName);
            storeLocalized.SEName = CommonHelper.EnsureMaximumLength(storeLocalized.SEName, 100);

            bool allFieldsAreEmpty = string.IsNullOrEmpty(storeLocalized.Name) &&
                string.IsNullOrEmpty(storeLocalized.Description) &&
                string.IsNullOrEmpty(storeLocalized.MetaKeywords) &&
                string.IsNullOrEmpty(storeLocalized.MetaDescription) &&
                string.IsNullOrEmpty(storeLocalized.MetaTitle) &&
                string.IsNullOrEmpty(storeLocalized.SEName);


            if (!_context.IsAttached(storeLocalized))
                _context.StoreLocalized.Attach(storeLocalized);

            if (allFieldsAreEmpty)
            {
                //delete if all fields are empty
                _context.DeleteObject(storeLocalized);
                _context.SaveChanges();
            }
            else
            {
                _context.SaveChanges();
            }

            if (this.StoresCacheEnabled)
            {
                _cacheManager.RemoveByPattern(STORES_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Deletes a product store mapping OK
        /// </summary>
        /// <param name="productManufacturerId">Product store mapping identifer</param>
        public void DeleteProductStore(int productStoreId)
        {
            if (productStoreId == 0)
                return;

            var productStore = GetProductStoreById(productStoreId);
            if (productStore == null)
                return;


            if (!_context.IsAttached(productStore))
                _context.ProductStores.Attach(productStore);
            _context.DeleteObject(productStore);
            _context.SaveChanges();

            if (this.StoresCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(STORES_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTSTORES_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Gets product store collection OK
        /// </summary>
        /// <param name="manufacturerId">Store identifier</param>
        /// <returns>Product store collection</returns>
        public List<ProductStore> GetProductStoresByStoreId(int storeId)
        {
            if (storeId == 0)
                return new List<ProductStore>();

            bool showHidden = NopContext.Current.IsAdmin;
            string key = string.Format(PRODUCTSTORES_ALLBYSTORERID_KEY, showHidden, storeId);
            object obj2 = _cacheManager.Get(key);
            if (this.MappingsCacheEnabled && (obj2 != null))
            {
                return (List<ProductStore>)obj2;
            }


            var query = from pm in _context.ProductStores
                        join p in _context.Products on pm.ProductID equals p.ProductId
                        where pm.StoreID == storeId &&
                        !p.Deleted &&
                        (showHidden || p.Published)
                        orderby pm.DisplayOrder
                        select pm;
            var productStores = query.ToList();

            if (this.MappingsCacheEnabled)
            {
                _cacheManager.Add(key, productStores);
            }
            return productStores;
        }

        /// <summary>
        /// Gets a product store mapping collection  OK
        /// </summary>
        /// <param name="productId">Product identifier</param>
        /// <returns>Product store mapping collection</returns>
        public List<ProductStore> GetProductStoresByProductId(int productId)
        {
            if (productId == 0)
                return new List<ProductStore>();

            bool showHidden = NopContext.Current.IsAdmin;
            string key = string.Format(PRODUCTSTORES_ALLBYSTORERID_KEY, showHidden, productId);
            object obj2 = _cacheManager.Get(key);
            if (this.MappingsCacheEnabled && (obj2 != null))
            {
                return (List<ProductStore>)obj2;
            }

            
            var query = from pm in _context.ProductStores
                        join m in _context.Stores on pm.StoreID equals m.StoreId
                        where pm.ProductID == productId &&
                        !m.Deleted &&
                        (showHidden || m.Published)
                        orderby pm.DisplayOrder
                        select pm;
            var productStores = query.ToList();

            if (this.MappingsCacheEnabled)
            {
                _cacheManager.Add(key, productStores);
            }
            return productStores;
        }

        /// <summary>
        /// Gets a product store mapping  OK
        /// </summary>
        /// <param name="productManufacturerId">Product store mapping identifier</param>
        /// <returns>Product store mapping</returns>
        public ProductStore GetProductStoreById(int productStoreId)
        {
            if (productStoreId == 0)
                return null;

            string key = string.Format(PRODUCTSTORES_BY_ID_KEY, productStoreId);
            object obj2 = _cacheManager.Get(key);
            if (this.MappingsCacheEnabled && (obj2 != null))
            {
                return (ProductStore)obj2;
            }


            var query = from pm in _context.ProductStores
                        where pm.ProductStoreID == productStoreId
                        select pm;
            var productStore = query.SingleOrDefault();

            if (this.MappingsCacheEnabled)
            {
                _cacheManager.Add(key, productStore);
            }
            return productStore;
        }

        /// <summary>
        /// Inserts a product manufacturer mapping  OK
        /// </summary>
        /// <param name="productManufacturer">Product manufacturer mapping</param>
        public void InsertProductStore(ProductStore productStore)
        {
            if (productStore == null)
                throw new ArgumentNullException("productStore");



            _context.ProductStores.AddObject(productStore);
            _context.SaveChanges();

            if (this.ManufacturersCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(STORES_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTSTORES_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Updates the product store mapping OK
        /// </summary>
        /// <param name="productManufacturer">Product manufacturer mapping</param>
        public void UpdateProductStore(ProductStore productStore)
        {
            if (productStore == null)
                throw new ArgumentNullException("productStore");


            if (!_context.IsAttached(productStore))
                _context.ProductStores.Attach(productStore);

            _context.SaveChanges();

            if (this.ManufacturersCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(STORES_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTSTORES_PATTERN_KEY);
            }
        }
        #endregion

        #region Properties

        /// <summary>
        /// Gets a value indicating whether manufacturers cache is enabled
        /// </summary>
        public bool ManufacturersCacheEnabled
        {
            get
            {
                return IoC.Resolve<ISettingManager>().GetSettingValueBoolean("Cache.ManufacturerManager.ManufacturersCacheEnabled");
            }
        }

        public bool StoresCacheEnabled
        {
            get
            {
                return IoC.Resolve<ISettingManager>().GetSettingValueBoolean("Cache.StoreManager.StoreCacheEnabled");
            }
        }

        /// <summary>
        /// Gets a value indicating whether mappings cache is enabled
        /// </summary>
        public bool MappingsCacheEnabled
        {
            get
            {
                return IoC.Resolve<ISettingManager>().GetSettingValueBoolean("Cache.ManufacturerManager.MappingsCacheEnabled");
            }
        }
        #endregion
    }
}
